package git.soulbgm;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.string.StringEncoder;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

/**
 * TCP服务端
 *
 * @author SoulBGM
 * @date 2022/04/19 23:44
 */
public class TcpServer {

    private final LogUtil log = new LogUtil(getClass());

    /**
     * 数据进入处理器
     */
    private ChannelInboundHandlerAdapter handler;

    private ServerBootstrap server;
    private EventLoopGroup bossGroup;
    private EventLoopGroup workerGroup;

    public void initConfig(int bossGroupNum, int workerGroupNum, ChannelInboundHandlerAdapter handler) {
        this.handler = handler;
        ByteBuf delimiter = Unpooled.copiedBuffer(new byte[]{120, 120, 120, 120, -120, -120, -120, -120});
        server = new ServerBootstrap();
        // 1、绑定两个线程组分别处理客户端通道的accept和读写事件
        bossGroup = new NioEventLoopGroup(bossGroupNum);
        workerGroup = new NioEventLoopGroup(workerGroupNum);
        server.group(bossGroup, workerGroup);
        // 2、绑定服务器通道NioServerSocketChannel
        server.channel(NioServerSocketChannel.class)
                // 保持连接数
                .option(ChannelOption.SO_BACKLOG, 30000)
                // 有数据立即发送
                // .option(ChannelOption.TCP_NODELAY, true)
                // 保持连接
                .childOption(ChannelOption.SO_KEEPALIVE, true)
                // 处理新连接
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    // 初始化通道
                    @Override
                    protected void initChannel(SocketChannel ch) throws Exception {
                        // 3、给读写事件的线程通道绑定handler去真正处理读写
                        ch.pipeline().addLast(new DelimiterBasedFrameDecoder(Integer.MAX_VALUE, delimiter));
                        ch.pipeline().addLast(handler);
                    }
                });
    }

    public ChannelFuture bind(int bindPort) {
        // 4、监听端口 同步的返回成功或失败
        ChannelFuture[] futures = {null};
        CountDownLatch latch = new CountDownLatch(1);
        server.bind(bindPort).addListeners(new ChannelFutureListener() {
            @Override
            public void operationComplete(ChannelFuture future) throws Exception {
                futures[0] = future;
                latch.countDown();
            }
        });
        try {
            boolean result = latch.await(10, TimeUnit.SECONDS);
            if (result) {
                return futures[0];
            }
        } catch (InterruptedException e) {
            log.error("", e);
        }
        return null;
    }

}
